<template>
  <div class="layout-padding">
    <div class="layout-padding-auto layout-padding-view">
      <div class="flex h-screen overflow-hidden">

        <!--  左侧知识库列表 -->
        <div class="w-1/4 bg-white border-r border-gray-300">
          <knowleges-list @refresh="selectKnowledge"/>
        </div>

        <!-- 右侧聊天窗口 -->
        <div class="w-3/4 flex-1">
          <!-- 顶部操作栏-->
          <header class="bg-white text-gray-700 flex justify-end">
            <svg t="1711092183051" @click="clearStoreMessageList" class="w-6 h-6" viewBox="0 0 1024 1024" version="1.1"

                 xmlns="http://www.w3.org/2000/svg" p-id="5251" width="128" height="128">
              <path
                  d="M274.56 798.997333l19.434667-25.130666-33.792 68.565333a18.133333 18.133333 0 0 0 11.562666 25.536l59.733334 16a18.133333 18.133333 0 0 0 17.28-4.48c20.522667-19.818667 35.626667-35.989333 45.290666-48.469333l19.456-25.130667-33.813333 68.565333a18.133333 18.133333 0 0 0 11.562667 25.536l84.48 22.634667a18.133333 18.133333 0 0 0 17.28-4.48c20.522667-19.84 35.626667-35.989333 45.269333-48.469333l19.456-25.130667-33.813333 68.565333A18.133333 18.133333 0 0 0 535.530667 938.666667l72.106666 19.328a18.133333 18.133333 0 0 0 17.28-4.48c20.522667-19.84 35.626667-36.010667 45.269334-48.490667l19.456-25.130667-33.813334 68.586667a18.133333 18.133333 0 0 0 11.584 25.514667l86.421334 23.338666 3.84-0.213333c13.269333-0.704 29.056-5.034667 43.84-12.8 29.781333-15.701333 48.170667-43.2 52.181333-78.250667 2.133333-18.517333 4.778667-38.549333 8.405333-63.530666 1.642667-11.221333 2.944-20.010667 6.229334-41.834667 11.050667-73.322667 14.634667-101.034667 17.130666-133.674667l0.938667-12.373333 2.837333-2.922667 12.330667-1.344a41.813333 41.813333 0 0 0 24.810667-11.221333c10.730667-10.24 14.805333-25.386667 11.093333-42.197333l-37.546667-171.584c-3.029333-13.696-11.264-27.946667-23.146666-39.829334-11.648-11.626667-25.92-20.138667-39.893334-23.893333L723.626667 331.306667l-2.261334-3.925334L774.250667 130.133333c8.32-31.061333-11.754667-63.744-44.970667-72.64l-79.509333-21.312c-33.194667-8.896-66.922667 9.365333-75.264 40.426667l-52.842667 197.269333-3.925333 2.261334-118.101334-31.637334c-13.994667-3.754667-30.634667-3.498667-46.506666 0.746667-16.256 4.352-30.506667 12.586667-39.957334 22.933333l-118.314666 129.792c-11.605333 12.714667-15.658667 27.84-11.52 42.090667 4.16 14.229333 15.850667 25.194667 32.896 30.528l13.610666 4.266667 2.133334 3.882666-3.626667 13.802667c-21.12 79.850667-52.885333 136.917333-85.717333 150.890667-47.530667 20.202667-72.938667 49.429333-78.421334 85.034666-5.034667 32.682667 9.28 67.114667 37.589334 91.541334l22.037333 8.341333 74.666667 20.010667a42.666667 42.666667 0 0 0 41.216-11.050667c15.274667-15.274667 26.88-28.032 34.837333-38.293333z m551.381333-396.565333c14.144 3.797333 29.952 19.2 32.768 32l34.56 157.781333a10.666667 10.666667 0 0 1-13.184 12.586667L240.64 433.493333a10.666667 10.666667 0 0 1-5.12-17.493333l108.8-119.36c8.832-9.685333 30.229333-15.146667 44.373333-11.349333l141.333334 37.866666a21.333333 21.333333 0 0 0 26.133333-15.082666l58.304-217.642667a21.333333 21.333333 0 0 1 26.133333-15.082667l77.056 20.650667a21.333333 21.333333 0 0 1 15.082667 26.133333l-58.325333 217.642667a21.333333 21.333333 0 0 0 15.082666 26.112l136.448 36.565333zM315.456 701.568c-33.664 45.141333-64.597333 79.082667-92.8 101.802667l-5.909333 4.778666-2.837334 0.597334-88.106666-24.106667-2.922667-3.2c-13.034667-14.165333-19.370667-31.04-16.981333-46.592 3.285333-21.333333 22.058667-39.338667 53.205333-52.586667 31.722667-13.482667 59.818667-47.104 82.922667-99.904 10.026667-22.954667 18.88-48.725333 26.389333-76.586666l3.882667-14.4 3.904-2.261334 566.165333 151.701334 2.346667 3.306666-0.789334 12.224c-1.984 30.592-30.336 229.397333-32.128 244.906667-2.346667 20.416-11.306667 34.986667-27.605333 44.394667a73.237333 73.237333 0 0 1-21.397333 8.106666l-5.013334 0.725334-60.373333-16.170667 11.242667-20.288c8.277333-14.976 22.656-43.84 43.093333-86.613333a21.12 21.12 0 0 0-9.962667-28.16l-3.136-1.493334a21.333333 21.333333 0 0 0-26.261333 6.485334c-33.642667 45.056-64.533333 78.912-92.672 101.546666l-5.909333 4.757334-2.837334 0.597333-52.544-14.08 11.114667-20.266667c3.562667-6.485333 7.04-13.013333 10.453333-19.626666 7.04-13.504 17.898667-35.797333 32.597334-66.816a21.290667 21.290667 0 0 0-9.984-28.309334l-3.029334-1.450666a21.333333 21.333333 0 0 0-26.368 6.442666c-33.6 45.013333-64.469333 78.826667-92.608 101.482667l-5.909333 4.757333-2.837333 0.597334-52.138667-13.973334 11.114667-20.266666c3.242667-5.888 6.72-12.416 10.453333-19.626667 6.997333-13.461333 17.962667-35.946667 32.896-67.434667a20.970667 20.970667 0 0 0-10.112-28.010666l-3.328-1.536a21.333333 21.333333 0 0 0-26.069333 6.613333c-33.642667 45.056-64.554667 78.976-92.778667 101.696l-5.909333 4.757333-2.837334 0.597334-32.64-8.746667 11.093334-20.245333c3.541333-6.506667 7.04-13.034667 10.453333-19.626667 6.976-13.482667 17.941333-35.968 32.874667-67.456a21.056 21.056 0 0 0-10.069334-28.074667l-3.242666-1.514666a21.333333 21.333333 0 0 0-26.154667 6.549333z"
                  fill="#333333" p-id="5252"></path>
            </svg>
          </header>
          <!-- 聊天内容区   -->
          <div class="flex flex-col h-screen">
            <el-scrollbar height="60%" ref="scrollbarRef">
              <div class="flex-1 mx-2 mb-2" ref="chatListDom">
                <!-- 欢迎语区 -->
                <div
                    class="group flex flex-col px-4 py-3 rounded-lg"
                >
                  <div class="chat chat-start">
                    <div class="chat-image avatar">
                      <div v-if="selectedKnowledge?.avatarUrl.includes('svg')"
                           v-html="selectedKnowledge?.avatarUrl"/>
                      <div class="w-[30px] h-[30px] rounded-full " v-else>
                        <img :src="baseURL + selectedKnowledge.avatarUrl"
                             class="Tailwind CSS chat bubble component"/>
                      </div>
                    </div>
                    <div class="chat-bubble bg-white border-2 w-full">
                      <div class="flex flex-col md:mb-auto gap-1 flex-1 p-2">
                        <template v-for="(item, index) in prologueList" :key="index">
                          <h2 class="flex items-center m-auto text-lg font-bold ">
                            <MdRenderer v-if="item.type === 'md'" :source="item.str"/>
                          </h2>
                          <ul class="flex flex-col w-full m-auto">
                            <li class="w-full bg-gray-100 text-gray-700 p-3 rounded-md"
                                @click="quickProblemHandle(item.str)"
                                v-if="item.type === 'question'">
                              <el-icon>
                                <EditPen/>
                              </el-icon>
                              {{ item.str }}
                            </li>
                          </ul>
                        </template>
                      </div>
                    </div>
                  </div>
                </div>

                <!--  聊天区 -->
                <div
                    class="group flex flex-col px-4 py-3 rounded-lg"
                    v-for="(item,index) of messageList"
                >
                  <!--   ChatGPT 返回内容-->
                  <div v-if="item.role === 'assistant'">
                    <div class="chat chat-start" v-if="item.content">
                      <div class="chat-image avatar">
                        <div v-if="selectedKnowledge?.avatarUrl.includes('svg')"
                             v-html="selectedKnowledge?.avatarUrl"/>
                        <div class="w-[30px] h-[30px] rounded-full " v-else>
                          <img :src="baseURL + selectedKnowledge.avatarUrl"
                               class="Tailwind CSS chat bubble component"/>
                        </div>
                      </div>
                      <div class="chat-header">
                        AI 助手
                        <time class="text-xs opacity-50">{{
                            item.time
                          }}
                        </time>
                        <el-button @click="copyText(item.content)" class="w-4 h-4" text icon="CopyDocument"
                                   v-if="item.content" type="primary">
                        </el-button>
                        <el-button @click="regenerateText()" class="w-4 h-4 !ml-0" text icon="Refresh"
                                   v-if="item === messageList[messageList.length - 1] && item.content && messageList.length > 1"
                                   type="primary">
                        </el-button>
                      </div>
                      <div class="chat-bubble bg-white border-2">
                        <MdRenderer :source="item.content" v-if="selectedKnowledge.id !== '-4'"/>
                        <MindMap v-else :text="item.content" :id="item.time"/>
                      </div>
                      <div class="chat-footer opacity-50">
                        <div class="flex justify-between items-center" v-if="item.extLinks && item.extLinks.length > 0">

                          <!-- ext links 相关内容在 如上div 的下方-->
                          <div
                              class="ml-4 text-sm py-2 px-4 text-gray-400">
                            参考资料：
                            <el-tag class="ml-2" v-for="link in item.extLinks" type="info">{{ link.name }}</el-tag>

                            <!-- 评分-->
                            <div class="rating rating-sm ml-4" v-if="item.extLinks[0].distance">
                              <input v-for="n in 5" :key="n" type="radio" :name="'rating'+index"
                                     class="mask mask-star bg-gray-400"
                                     :checked="Math.ceil(1 / item.extLinks[0].distance) === n"
                              >
                            </div>
                          </div>
                        </div>

                        <el-button @click="stopGenerateText()" text icon="VideoPause"
                                   v-if="item === messageList[messageList.length - 1] && item.content && messageList.length > 1 && isTalking"
                                   type="primary">
                        </el-button>
                      </div>
                    </div>

                    <!-- 加载大模型消息的时候的等待框-->
                    <div class="flex" v-if="!item.content">
                      <div class="flex  ml-8 items-center justify-center text-center">
                        <span class="loading loading-ball loading-xs"></span>
                        <span class="loading loading-ball loading-sm"></span>
                        <span class="loading loading-ball loading-md"></span>
                        <span class="loading loading-ball loading-lg"></span>
                      </div>
                    </div>
                  </div>
                  <!--   用户输入的内容-->
                  <div v-if="item.role === 'user'">
                    <div class="chat chat-end ">
                      <div class="chat-image avatar">
                        <div class="w-10 rounded-full">
                          <img alt="Tailwind CSS chat bubble component"
                               :src="baseURL + roleAlias[item.role]"/>
                        </div>
                      </div>
                      <div class="chat-header">
                        <time class="text-xs opacity-50">{{ item.time }}</time>
                      </div>
                      <div class="chat-bubble bg-white border-2">
                        <MdRenderer v-if="item.content" :source="item.content"/>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </el-scrollbar>
          </div>
          <!-- 输入区 -->
          <div class="sticky bottom-0 w-full ml-2">
            <div
                class="flex w-full items-center rounded-md bg-slate-50 dark:bg-slate-900"
            >
              <label for="prompt" class="sr-only">Enter your prompt</label>
              <div class="flex justify-center space-x-2">
                <button
                    class="hover:text-blue-600 dark:text-slate-200 dark:hover:text-blue-600"
                    type="button"
                    @click="openDialog"
                >
                  <svg
                      xmlns="http://www.w3.org/2000/svg"
                      class="h-8 w-8"
                      aria-hidden="true"
                      viewBox="0 0 24 24"
                      stroke-width="2"
                      stroke="currentColor"
                      fill="none"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                  >
                    <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
                    <path d="M12 5l0 14"></path>
                    <path d="M5 12l14 0"></path>
                  </svg>
                </button>

                <button
                    class="hover:text-blue-600 dark:text-slate-200 dark:hover:text-blue-600"
                    type="button"
                    @click="audioRef.openDialog"
                >
                  <svg t="1723604425873" class="h-6 w-6" viewBox="0 0 1024 1024" version="1.1"
                       xmlns="http://www.w3.org/2000/svg" p-id="4335" width="256" height="256">
                    <path
                        d="M483.363 517.9h-53.357v53.348h53.357V517.9z m-160.051 0v53.348h53.348V517.9h-53.348z m213.398 53.348h53.348V517.9H536.71v53.348z m160.051 0V517.9h-53.347v53.348h53.347z m-266.755 53.365v53.348h53.357v-53.348h-53.357z m-106.694 0l19.802 53.348h33.545v-53.348h-53.347z m213.398 53.348h53.348v-53.348H536.71v53.348z m-106.704 69.748l53.357 10.273v-26.674h-53.357v16.401z m106.704 5.514l53.348-8.576v-13.338H536.71v21.914z m106.704-75.262h38.922l14.425-53.348h-53.347v53.348zM536.71 464.553h-53.347V517.9h53.347v-53.347z m-106.704 0h-53.347V517.9h53.347v-53.347zM590.058 517.9h53.356v-53.347h-53.356V517.9zM483.363 624.613h53.347v-53.365h-53.347v53.365z m-53.357-53.365h-53.347v53.365h53.347v-53.365z m160.052 53.365h53.356v-53.365h-53.356v53.365z m-106.695 53.348v53.348h53.347v-53.348h-53.347z m-106.704 0v36.746l53.347 16.602v-53.348h-53.347z m213.399 53.348l53.356-17.449v-35.898h-53.356v53.347z m106.703-160.061v53.365l17.414-35.896v-17.469h-17.414zM536.71 464.553h53.348v-53.348H536.71v53.348z m160.051 0v-53.348h-53.347v53.348h53.347z m-213.398-53.347h-53.357v53.348h53.357v-53.348z m-160.051 0v53.348h53.348v-53.348h-53.348z m106.694-53.348h-53.347v53.348h53.347v-53.348z m106.704 0h-53.347v53.348h53.347v-53.348z m53.348 53.348h53.356v-53.348h-53.356v53.348z m-53.348-53.348h53.348v-53.347H536.71v53.347z m160.051 0v-53.347h-53.347v53.347h53.347z m-213.398-53.347h-53.357v53.347h53.357v-53.347z m-160.051 0v53.347h53.348v-53.347h-53.348z m106.694-53.347h-53.347v53.347h53.347V144.45z m106.704 53.347V144.45h-53.347v53.347h53.347z m53.348 0h53.356V144.45h-53.356v53.347z m0-53.347V91.103H536.71v53.347h53.348z m106.703 0l-53.347-53.347v53.347h53.347z m-213.398 0V91.103h-53.357v53.347h53.357zM363.58 104.846l-40.269 39.604h53.348V91.103l-13.079 13.743z m173.13-67.091h-53.347v53.348h53.347V37.755zM430.006 64.429l-26.674 13.337-26.673 13.337h53.347V64.429zM624.092 78.08l-34.034-13.65v26.674h53.356L624.092 78.08z"
                        fill="" p-id="4336"></path>
                    <path
                        d="M847.257 554.738c0-16.934-5.533-27.965-15.551-27.965-10.938 0-15.568 11.031-15.568 27.965 0 162.92-169.403 303.777-306.166 303.777-155.836 0-305.77-152-305.77-304.184 0-16.934-9.233-21.527-15.098-21.527-6.42 0-16.427 5-16.427 21.934 0 175.906 151.252 320.232 323.128 335.746v72.512h-169.81c-16.952 0-30.667 5.609-30.667 18.281 0 11.824 13.715 15.365 30.667 15.365h367.953c16.953 0 30.667-2.951 30.667-15.346 0-13.283-13.714-18.301-30.667-18.301H526.499v-72.512c171.877-15.512 320.758-159.838 320.758-335.745zM509.972 769.383c118.547 0 214.644-96.125 214.644-214.645V248.12c0-118.537-96.097-214.644-214.644-214.644-118.546 0-214.644 96.106-214.644 214.644v306.619c0 118.519 96.097 214.644 214.644 214.644zM328.163 248.12c0-101.197 75.852-183.248 181.809-183.248 97.397 3.247 180.73 75.262 183.387 183.248v306.619c0 97.971-73.104 185.332-183.387 185.332-110.394 0-181.809-85.408-181.809-185.332V248.12z"
                        fill="" p-id="4337"></path>
                  </svg>
                </button>
              </div>
              <textarea
                  v-model="messageContent"
                  id="chat"
                  rows="3"
                  @keydown.enter.prevent="isTalking ? null:sendOrSave()"
                  :placeholder="placeholder"
                  class="mx-2 flex min-h-full w-full rounded-md border border-slate-200 p-2 text-base text-slate-900 placeholder-slate-400 focus:border-blue-600 focus:outline-none focus:ring-1 focus:ring-blue-600 dark:border-slate-300/20 dark:bg-slate-800 dark:text-slate-200 dark:placeholder-slate-400 dark:focus:border-blue-600 dark:focus:ring-blue-600"
              ></textarea>
              <div>
                <button
                    type="submit" @click="isTalking ? null : sendOrSave()"
                    class="inline-flex hover:text-blue-600 dark:text-slate-200 dark:hover:text-blue-600 sm:p-2"
                >
                  <svg
                      xmlns="http://www.w3.org/2000/svg"
                      class="h-6 w-6"
                      aria-hidden="true"
                      viewBox="0 0 24 24"
                      stroke-width="2"
                      stroke="currentColor"
                      fill="none"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                  >
                    <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
                    <path d="M10 14l11 -11"></path>
                    <path
                        d="M21 3l-6.5 18a.55 .55 0 0 1 -1 0l-3.5 -7l-7 -3.5a.55 .55 0 0 1 0 -1l18 -6.5"
                    ></path>
                  </svg>
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 提示词抽屉 -->
      <prompts-dialog ref="promptsRef" @refresh="selectPrompt"/>
      <func-dialog ref="funcsRef" @refresh="selectFunc"/>
      <table-dialog ref="tablesRef" @refresh="selectTable"/>
      <audio-dialog ref="audioRef" @refresh="selectPrompt"/>
    </div>
  </div>
</template>

<script setup lang="ts">
import type {ChatMessage, Dataset, Table} from "/@/views/aiknowledge/aiChat/ts/index";
import MdRenderer from '/@/components/MdRenderer/MdRenderer.vue'
import MindMap from '/@/components/MindMap/index.vue'
import {parseTime} from "/@/utils/formatTime";
import {useUserInfo} from "/@/stores/userInfo";
import commonFunction from "/@/utils/commonFunction";
import {Local, Session} from "/@/utils/storage";
import {validateNull} from "/@/utils/validate";
import {useMessage} from "/@/hooks/message";
import {useEventSource} from "@vueuse/core";
import {initSseConnection, deleteConversation, defaultWelcomeMessage} from "./ts/gpt";


const {copyText} = commonFunction();
const PromptsDialog = defineAsyncComponent(() => import('./prompts.vue'));
const FuncDialog = defineAsyncComponent(() => import('./functions.vue'));
const KnowlegesList = defineAsyncComponent(() => import('./knowleges.vue'));
const TableDialog = defineAsyncComponent(() => import('./tables.vue'));
const AudioDialog = defineAsyncComponent(() => import('./audio.vue'));

let isTalking = ref(false);
let videoDialogVisible = ref(false);
let messageContent = ref("");
let placeholder = ref("Your message...");
const promptsRef = ref()
const funcsRef = ref()
const tablesRef = ref()
const audioRef = ref()
const functionName = ref()
const tableObj = ref<Table>({
  dsName: 'master',
  tableNames: ['ai_bill'],
})
const chatListDom = ref<HTMLDivElement>();
const scrollbarRef = ref()
const roleAlias = {user: useUserInfo().userInfos.user.avatar, assistant: "AI 助手", system: "System"};
const messageList = ref<ChatMessage[]>([])

/**
 * 从会话存储中获取访问令牌
 * @returns {string} 访问令牌
 */
const token = computed(() => {
  return Session.getToken();
});
/**
 * 从会话存储中获取访问租户
 * @returns {string} 租户
 */
const tenant = computed(() => {
  return Session.getTenant();
});


const sendChatMessage = async (content: string = messageContent.value) => {
  if (selectedKnowledge.value?.id === "-1" && validateNull(functionName.value)) {
    useMessage().warning('请选择目标表单功能')
    funcsRef.value.openDialog()
    return
  }

  if (selectedKnowledge.value?.id === "-2" && validateNull(tableObj.value)) {
    useMessage().warning('请选择目标操作的表')
    tablesRef.value.openDialog()
    return
  }

  const requestMessage: ChatMessage = {
    conversationId: `chat-message-list-${selectedKnowledge.value.id}-${useUserInfo().userInfos.user.userId}-${token.value}`,
    role: "user",
    content,
    time: parseTime(new Date()),
    datasetId: selectedKnowledge.value.id,
    extDetails: {
      table: tableObj.value,
      funcName: functionName.value,
    }
  }

  try {
    isTalking.value = true;
    messageList.value.push(requestMessage);
    clearMessageContent();
    messageList.value.push({role: "assistant", content: ""});

    nextTick(() => {
      scrollToBottom()
    })

    // 发送消息
    const {data} = await initSseConnection(requestMessage);
    sseMessageSend(data)
  } catch (error: any) {
    appendLastMessageContent({message: '网络通信超时，请稍后再试'});
    isTalking.value = false;
  }
};


/**
 * 创建websocket 链接
 */
const eventSourceRef = ref();
const sseMessageSend = (messageKey: string) => {
  //  baseURL
  const baseURL = import.meta.env.VITE_API_URL;
  const {
    eventSource,
    error
  } = useEventSource(`${baseURL}/${import.meta.env.VITE_IS_MICRO == 'false' ? '/admin' : '/knowledge'}/chat/msg/list?access_token=${token.value}&TENANT-ID=${tenant.value}&key=${messageKey}`, [], {
    autoReconnect: {
      retries: 1,
      delay: 1000,
      onFailed() {
        appendLastMessageContent({message: '网络通信超时，请稍后再试'});
        isTalking.value = false;
      },
    },
  })

  try {
    eventSourceRef.value = eventSource
    if (!error.value) {
      eventSource.value?.addEventListener('message', (result) => {
        let resultData = JSON.parse(result.data)
        if (eventSource.value?.OPEN && resultData.message === '[DONE]') {
          eventSource.value?.close()
          // 写入到 LocalStorage
          const key = `chat-message-list-${selectedKnowledge.value.id}-${useUserInfo().userInfos.user.userId}`
          Local.set(key, JSON.stringify(messageList.value))
          isTalking.value = false;
          return
        }
        if (eventSource.value?.OPEN && resultData.message !== 'pong') {
          appendLastMessageContent({message: resultData.message, extLinks: resultData.extLinks});
          nextTick(() => {
            scrollToBottom()
          })
        }
      });
    } else {
      appendLastMessageContent({message: '网络通信超时，请稍后再试'});
      isTalking.value = false;
    }
  } catch (e) {
    appendLastMessageContent({message: '网络通信超时，请稍后再试'});
    isTalking.value = false;
  }
};

const appendLastMessageContent = (result: any) => {
  messageList.value[messageList.value.length - 1].content += result.message
  messageList.value[messageList.value.length - 1].time = parseTime(new Date())
  messageList.value[messageList.value.length - 1].extLinks = result.extLinks
}

const sendOrSave = async () => {
  if (!messageContent.value.length) return;
  await sendChatMessage();
};


const selectedKnowledge = ref<Dataset>(defaultWelcomeMessage[0]);
const selectKnowledge = (knowledge: Dataset) => {
  selectedKnowledge.value = knowledge
  placeholder.value = knowledge.placeholder || "请输入您的问题"
  const key = `chat-message-list-${selectedKnowledge.value.id}-${useUserInfo().userInfos.user.userId}`
  if (!validateNull(Local.get(key))) {
    messageList.value = JSON.parse(Local.get(key))
  } else {
    messageList.value = []
  }
}

const isMdArray = (val: string) => val.match(/^-\s.*/m)
const prologueList = computed(() => {
  const lines = selectedKnowledge.value.welcomeMsg?.split('\n')
  return lines
      .reduce((pre_array: Array<any>, current: string, index: number) => {
        const currentObj = isMdArray(current)
            ? {
              type: 'question',
              str: current.replace(/^-\s+/, ''),
              index: index
            }
            : {
              type: 'md',
              str: current,
              index: index
            }
        if (pre_array.length > 0) {
          const pre = pre_array[pre_array.length - 1]
          if (!isMdArray(current) && pre.type == 'md') {
            pre.str = [pre.str, current].join('\n')
            pre.index = index
            return pre_array
          } else {
            pre_array.push(currentObj)
          }
        } else {
          pre_array.push(currentObj)
        }
        return pre_array
      }, [])
      .sort((pre: any, next: any) => pre.index - next.index)
})

function quickProblemHandle(val: string) {
  if (isTalking.value === false) {
    messageContent.value = val
    sendChatMessage(val)
  }
}

const openDialog = () => {
  if (selectedKnowledge.value?.id === "0") {
    promptsRef.value.openDialog()
  } else if (selectedKnowledge.value?.id === "-1") {
    funcsRef.value.openDialog()
  } else if (selectedKnowledge.value?.id === "-2") {
    tablesRef.value.openDialog()
  }
};

const selectPrompt = (prompt: string) => {
  messageContent.value = prompt
}

const selectFunc = (func: { funcDesc: string, funcName: string }) => {
  const key = `chat-message-list-${selectedKnowledge.value.id}-${useUserInfo().userInfos.user.userId}-${token.value}`
  // 调用后台缓存
  deleteConversation(key)
  placeholder.value = func.funcDesc;
  functionName.value = func.funcName;

  // 发送
  sendOrSave()
}

const selectTable = (table: { dsName: string, tableNames: string[] }) => {
  tableObj.value = {
    dsName: table.dsName,
    tableNames: table.tableNames
  }

  // 发送
  sendOrSave()
}

const clearMessageContent = () => (messageContent.value = "");

const clearStoreMessageList = () => {
  const key = `chat-message-list-${selectedKnowledge.value.id}-${useUserInfo().userInfos.user.userId}`

  // 调用后台缓存
  deleteConversation(`${key}-${token.value}`)
  Local.remove(key)
  eventSourceRef?.value?.value?.close()
  // 清空会话
  messageList.value = []
  clearMessageContent()
}
const scrollToBottom = () => {
  if (!chatListDom.value) return;
  scrollbarRef.value!.setScrollTop(chatListDom.value!.clientHeight)
};

// 重新生成
const regenerateText = async () => {
  if (isTalking.value) return

  // 获取messageList 最后一个 role: "assistant" 的消息
  const lastAssistantMessage = messageList.value.slice().reverse().find(item => item.role === 'assistant')
  // 获取messageList 最后一个 role: "user" 的消息
  const lastUserMessage = messageList.value.slice().reverse().find(item => item.role === 'user')
  messageContent.value = lastUserMessage?.content || ''
  // 删除最后一个 role: "assistant" 的消息 和 最后一个 role: "user" 的消息
  messageList.value = messageList.value.filter(item => item !== lastAssistantMessage && item !== lastUserMessage)
  await sendChatMessage();
  // 写入到 LocalStorage
  const key = `chat-message-list-${selectedKnowledge.value.id}-${useUserInfo().userInfos.user.userId}`
  Local.set(key, JSON.stringify(messageList.value))
}

const stopGenerateText = async () => {
  eventSourceRef?.value?.value?.close()
  isTalking.value = false
}

</script>

<style scoped>
pre {
  font-family: -apple-system, "Noto Sans", "Helvetica Neue", Helvetica,
  "Nimbus Sans L", Arial, "Liberation Sans", "PingFang SC", "Hiragino Sans GB",
  "Noto Sans CJK SC", "Source Han Sans SC", "Source Han Sans CN",
  "Microsoft YaHei", "Wenquanyi Micro Hei", "WenQuanYi Zen Hei", "ST Heiti",
  SimHei, "WenQuanYi Zen Hei Sharp", sans-serif;
}

.btn {
  @apply px-4 py-2 text-sm font-medium tracking-wide text-white capitalize transition-colors duration-300 transform bg-blue-700 rounded-md hover:bg-blue-600 focus:outline-none focus:bg-blue-600 whitespace-nowrap disabled:bg-blue-300;
}

.input {
  @apply px-4 py-2 text-gray-700 bg-white border rounded-md mr-2 sm:mr-4 focus:border-blue-400 focus:outline-none focus:ring focus:ring-blue-300 focus:ring-opacity-40 flex-grow;
}

.chat-bubble:before {
	background-color: #e5e7eb;
}
.flex {
	display: flex;
}
.py-3 {
	padding-top: 12px;
	padding-bottom: 12px;
}
.px-4 {
	padding-left: 16px;
	padding-right: 16px;
}
.flex-col {
	flex-direction: column;
}
.chat-start {
	place-items: start;
	grid-template-columns: auto 1fr;
}
.chat {
	display: grid;
	/* grid-template-columns: repeat(2, minmax(0, 1fr)); */
	-moz-column-gap: 0.75rem;
	column-gap: 0.75rem;
	padding-top: 0.25rem;
	padding-bottom: 0.25rem;
}
.chat-end {
    place-items: end;
    grid-template-columns: 1fr auto;
}
.chat-start {
    place-items: start;
    grid-template-columns: auto 1fr;
}
.chat-start .chat-image {
	grid-column-start: 1;
}
.chat-image {
  width: 50px;
	grid-row: span 2 / span 2;
	align-self: flex-end;
  margin-bottom: -30px;
}
.avatar {
	position: relative;
	display: inline-flex;
}
.rounded-full {
	border-radius: 9999px;
}
.w-12 {
	width: 48px;
}
.h-12 {
	height: 48px;
}

.chat-start .chat-bubble {
	grid-column-start: 2;
	border-end-start-radius: 0px;
  width: 90%;
}
.bg-white {
	--tw-bg-opacity: 1;
	background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.border-2 {
	border-width: 2px;
}
.w-full {
	width: 100%;
}
.chat-bubble {
	position: relative;
	display: block;
	width: -moz-fit-content;
	width: fit-content;
	padding-left: 1rem;
	padding-right: 1rem;
	padding-top: 0.5rem;
	padding-bottom: 0.5rem;
	max-width: 90%;
	border-radius: var(--rounded-box, 1rem);
	min-height: 2.75rem;
	min-width: 2.75rem;
	--tw-bg-opacity: 1;
	background-color: var(--fallback-n, oklch(var(--n) / var(--tw-bg-opacity)));
	--tw-text-opacity: 1;
	color: var(--fallback-nc, oklch(var(--nc) / var(--tw-text-opacity)));
}
/* .chat-start .chat-bubble:before {
	inset-inline-start: -0.749rem;
} */
/* .chat-bubble:before {
	position: absolute;
	bottom: 0px;
	height: 0.75rem;
	width: 0.75rem;
	background-color: inherit;
	content: '';
	-webkit-mask-size: contain;
	mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: center;
	mask-position: center;
} */
</style>
